<?php

namespace App\Console\Commands\Amap;

use App\Models\Amap\AmapRegionModel;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class UpdateAmapRegion extends Command
{
    protected $signature   = 'update-amap-region {--force : 在生产环境中强制清空表}';
    protected $description = '从高德地图API更新中国行政区域数据';

    private const CHUNK_SIZE = 100;
    private const API_URL    = 'https://restapi.amap.com/v3/config/district';

    /**
     * 执行控制台命令的主入口
     */
    public function handle()
    {
        $this->info('开始更新高德地图行政区域数据...');

        try {
            ini_set('memory_limit', '1024M');

            // 清空现有数据表
            $this->truncateTable();

            $regions = $this->fetchAmapData();
            $this->processAndStoreRegions($regions);
            $this->info('行政区域数据更新完成。');
        } catch (\Exception $e) {
            Log::error('行政区域更新失败: ' . $e->getMessage(), ['trace' => $e->getTraceAsString()]);
            $this->error('更新失败: ' . $e->getMessage());
            return 1;
        }

        return 0;
    }

    /**
     * 清空数据表，处理外键约束并确保生产环境安全
     */
    private function truncateTable(): void
    {
        if (app()->environment('production') && !$this->option('force')) {
            throw new \RuntimeException('生产环境中需使用 --force 选项才能清空表');
        }

        try {
            // 禁用外键检查以避免约束冲突
            DB::statement('SET FOREIGN_KEY_CHECKS=0;');
            // 使用 DELETE 替代 TRUNCATE 以确保事务兼容性
            AmapRegionModel::query()->delete();
            // 恢复外键检查
            DB::statement('SET FOREIGN_KEY_CHECKS=1;');
            $this->info('数据表已成功清空。');
        } catch (\Exception $e) {
            // 确保外键检查恢复，即使发生错误
            DB::statement('SET FOREIGN_KEY_CHECKS=1;');
            throw new \RuntimeException('清空数据表失败: ' . $e->getMessage());
        }
    }

    /**
     * 从高德地图API获取行政区域数据
     * @return array API返回的区域数据
     * @throws \RuntimeException 如果API请求失败或响应无效
     */
    private function fetchAmapData(): array
    {
        $amapKey = '0fbbca3573a116363bd917cd9538e005';
        if (!$amapKey) {
            throw new \RuntimeException('未配置高德地图API密钥');
        }

        $response = Http::get(self::API_URL, [
            'keywords'    => '中国',
            'subdistrict' => 3,
            'key'         => $amapKey,
        ]);

        if ($response->failed()) {
            throw new \RuntimeException('高德地图API请求失败: ' . $response->status());
        }

        $data = $response->json();

        if (!isset($data['districts']) || $data['status'] !== '1') {
            throw new \RuntimeException('高德地图API响应格式无效');
        }

        return $data['districts'];
    }

    /**
     * 处理并存储行政区域数据（省、市、区）
     * @param array $china API返回的中国区域数据
     */
    private function processAndStoreRegions(array $china): void
    {
        $provinceList = [];
        $cityList     = [];
        $districtList = [];

        foreach ($china[0]['districts'] as $province) {
            if (!$this->isValidRegion($province)) {
                continue;
            }

            $provinceList[] = $this->formatRegion($province, 0, 1);

            foreach ($province['districts'] as $city) {
                if (!$this->isValidRegion($city)) {
                    continue;
                }

                $cityList[] = $this->formatRegion($city, $province['adcode'], 2);

                foreach ($city['districts'] as $district) {
                    if (!$this->isValidRegion($district)) {
                        continue;
                    }

                    $districtList[] = $this->formatRegion($district, $city['adcode'], 3);
                }
            }
        }

        $this->storeRegions('省份', $provinceList);
        $this->storeRegions('城市', $cityList);
        $this->storeRegions('区县', $districtList);
    }

    /**
     * 验证区域数据是否有效
     * @param array $region 区域数据
     * @return bool 数据是否有效
     */
    private function isValidRegion(array $region): bool
    {
        return !empty($region['name']) && !empty($region['adcode']);
    }

    /**
     * 格式化区域数据为数据库存储格式
     * @param array $region 区域数据
     * @param string $parentCode 父级区域代码
     * @param int $level 区域层级（1:省, 2:市, 3:区）
     * @return array 格式化后的区域数据
     */
    private function formatRegion(array $region, string $parentCode, int $level): array
    {
        return [
            'name'      => $region['name'],
            'code'      => $region['adcode'],
            'pCode'     => $parentCode,
            'level'     => $level,
            'createdAt' => time(),
            'updatedAt' => time(),
        ];
    }

    /**
     * 批量存储区域数据到数据库
     * @param string $type 区域类型（省份/城市/区县）
     * @param array $regions 区域数据列表
     */
    private function storeRegions(string $type, array $regions): void
    {
        if (empty($regions)) {
            $this->warn("没有{$type}数据需要存储");
            return;
        }

        $chunks      = array_chunk($regions, self::CHUNK_SIZE);
        $totalChunks = count($chunks);

        foreach ($chunks as $index => $chunk) {
            DB::transaction(function () use ($chunk) {
                AmapRegionModel::query()->insert($chunk);
            });

            $this->info(sprintf('已处理%s数据块 %d/%d', $type, $index + 1, $totalChunks));
        }
    }
}